/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package ssp.net;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import ssp.database.DatabaseManager;
import ssp.database.NetworkMap;
import ssp.topology.Node;
import ssp.utility.Pair;

/**
 * ネットワークコンポーネントを表すクラス
 * @author yamazaki
 */
public class NWcomponent implements Node {
    
    /**
     * ネットワークコンポーネントのID
     */
    private final int ID;
    
    /**
     * 隣接ネットワークコンポーネントのリスト
     */
    private List<Node> neighborNWcomponents;
    
    /**
     * ネットワークコンポーネント内の資源を管理する
     */
    private final NWresourceManager nwResourceManager;
    
    /**
     * コンストラクタ
     * @param ID ネットワークコンポーネントのID
     */
    public NWcomponent(int ID) {
        this.ID = ID;
        this.neighborNWcomponents = new ArrayList<Node>();
        this.nwResourceManager = new NWresourceManager();
    }

    /**
     * @return the ID
     */
    public int getID() {
        return ID;
    }

    /**
     * @return the NWresourceManager
     */
    public NWresourceManager getNWresourceManager() {
        return nwResourceManager;
    }

    @Override
    public void addNeighbor(Node neighbor) {
        this.neighborNWcomponents.add(neighbor);
    }

    @Override
    public boolean isNeighbor(Node other) {
        return this.neighborNWcomponents.contains(other);
    }

    @Override
    public void removeNeighbor(Node neighbor) {
        this.neighborNWcomponents.remove(neighbor);
    }
    
    /**
     * @return the nieghborNWcomponents
     */
    public List<Node> getNeighborNWcomponents() {
        return new ArrayList<Node>(this.neighborNWcomponents);
    }
    
    /**
     * 指定の2ノード間を結ぶリソースを管理に加える
     * @param c1 隣接ネットワークコンポーネント
     * @param c2 隣接ネットワークコンポーネント
     * @param bandwidthUnit 通信帯域の最小単位
     * @param QoSindexList QoS指標のリスト
     * @param capacity 許容可能量
     */
    public void registNWresourceEntry(Node c1, Node c2, double bandwidthUnit,double chargeUnit, List<Integer> QoSindexList, int capacity) {
        Set<Node> connectedNWcomponents = new HashSet<Node>();
        connectedNWcomponents.add(c1);
        connectedNWcomponents.add(c2);
        nwResourceManager.addNWresourceEntry(new NWresourceEntry(connectedNWcomponents, bandwidthUnit, chargeUnit, QoSindexList, capacity));
    }
    
    /**
     * 指定の2ノード間を結ぶリソースを変更する
     * @param c1 隣接ネットワークコンポーネント
     * @param c2 隣接ネットワークコンポーネント
     * @param bandwidthUnit 通信帯域の最小単位
     * @param QoSindexList QoS指標のリスト
     * @param capacity 許容可能量
     */
    public void updateNWresourceEntry(Node c1, Node c2, double bandwidthUnit, double chargeUnit, List<Integer> QoSindexList, int capacity) {
        NWresourceEntry entry = nwResourceManager.searchEntry(c1, c2);
        nwResourceManager.removeNWresourceEntry(entry);
        Set<Node> connectedNWcomponents = new HashSet<Node>();
        connectedNWcomponents.add(c1);
        connectedNWcomponents.add(c2);
        nwResourceManager.addNWresourceEntry(new NWresourceEntry(connectedNWcomponents, bandwidthUnit, chargeUnit, QoSindexList, capacity));
    }
    
    /**
     * ネットワークマップを更新する
     * @param c1 両端ノード
     * @param c2 両端ノード
     * @param currentTime 現在時刻
     */
    public void updateNWmap(Node c1, Node c2, double currentTime) {
        NWresourceEntry entry = nwResourceManager.searchEntry(c1, c2);
        Pair<Integer, Set<Node>> key = new Pair<Integer, Set<Node>>(this.getID(), new HashSet<Node>(entry.getConnectedNWcomponents()));
        NetworkMap DB = DatabaseManager.getINSTANCE().getNetworkMap();
        DB.updateBandwidthUnitTable(currentTime, key, entry.getBandwidthUnit());
        DB.updateQoSindexListTable(currentTime, key, new ArrayList<Integer>(entry.getQoSindexList()));
        DB.updateCapacityTable(currentTime, key, entry.getCapacity());
        int availability = entry.getCapacity() - entry.getReservedResource();
        DB.updateAvailabilityTable(currentTime, key, availability);
    }
    
    /**
     * ネットワークマップ上のavailabilityのみを更新する
     * @param c1 両端ノード
     * @param c2 両端ノード
     * @param currentTime 現在時刻
     */
    public void updateNWmapForAvailability(Node c1, Node c2, double currentTime) {
        NWresourceEntry entry = nwResourceManager.searchEntry(c1, c2);
        int availability = entry.getCapacity() - entry.getReservedResource();
        Pair<Integer, Set<Node>> key = new Pair<Integer, Set<Node>>(this.getID(), new HashSet<Node>(entry.getConnectedNWcomponents()));
        DatabaseManager.getINSTANCE().getNetworkMap().updateAvailabilityTable(currentTime, key, availability);
    }

    @Override
    public boolean equals(Object obj) {
        if (obj == null) {
            return false;
        }
        if (getClass() != obj.getClass()) {
            return false;
        }
        final NWcomponent other = (NWcomponent) obj;
        if (this.ID != other.ID) {
            return false;
        }
        return true;
    }

    @Override
    public int hashCode() {
        int hash = 5;
        hash = 97 * hash + this.ID;
        return hash;
    }

    @Override
    public String toString() {
        return "NWcomponent{" + "ID=" + ID + '}';
    }
    
}
